package org.wattdepot.gdata.kukuicup.updater.energylastthirtydays;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.gdata.kukuicup.service.GDataBatchRequest;
import org.wattdepot.gdata.kukuicup.service.GDataService;
import org.wattdepot.gdata.kukuicup.service.WattDepotService;
import org.wattdepot.gdata.kukuicup.updater.GDataCronTask;
import org.wattdepot.util.tstamp.Tstamp;
import it.sauronsoftware.cron4j.TaskExecutionContext;

/**
 * Gets the energy used by a source for the current day so far and each day of the last thirty days.
 * @author Philip Johnson
 */
public class EnergyLastThirtyDaysHistoricalTask extends GDataCronTask {
  
  /**
   * Creates the task that gets woken up once a day to get the daily energy consumption for 
   * the past 30 days.
   * @param wattDepotService The WattDepot service configuration data. 
   * @param gdataService The gdata service configuration data.
   * @param spreadsheetURL The URL to the spreadsheet containing the data.
   * @param sourceName The WattDepot source of interest.
   * @param isVirtual True if the source is virtual.
   * @param row The row in the spreadsheet that this source's data appears in.
   */
  public EnergyLastThirtyDaysHistoricalTask(WattDepotService wattDepotService, 
      GDataService gdataService,
      URL spreadsheetURL, String sourceName, boolean isVirtual, int row) {
    super(wattDepotService, gdataService, spreadsheetURL, sourceName, row, 
        "EnergyLastThirtyDays", isVirtual);
  }

  /**
   * The method called once a day to update the data for the last thirty days.
   * @param context Ignored.
   * @throws RuntimeException If problems occur (which they shouldn't). 
   */
  @Override
  public void execute(TaskExecutionContext context) throws RuntimeException {
    // Need to deal with missing data, like when sensors are not working. 
    System.out.format("%s Running EnergyLastThirtyDays (historical) for source %s%n", 
        getTimestamp(), sourceName);

    // Get the current time. 
    XMLGregorianCalendar currTime = Tstamp.makeTimestamp();

    // Get the daily energy values for the past 30 days.
    startWattDepotTiming();
    List<Integer> energies = getDailyEnergy(currTime);
    stopWattDepotTiming();

    startGDataTiming();
    
    // Add the actual data to the spreadsheet.
    GDataBatchRequest request = new GDataBatchRequest(gdataService, spreadsheetURL);
    try {
      // Add the last update field
      request.addRequest(this.row, 2, gdataService.makeLastUpdate(currTime));
      // Add the actual energy data. 
      for (int i = 0; i < 30; i++) {
        int energyValue = energies.get(i);
        // Only update the current value if the new value is greater than zero.
        if (energyValue > 0) {
          request.addRequest(this.row, i + 4, String.valueOf(energies.get(i))); 
        }
        else {
          printTaskResults("Last 30 Days", "Not updating entry", String.valueOf(i));
        }
      }
      // Send the request.
      request.sendRequest();
    }
    catch (Exception e) {
      printTaskResults("Last 30 Days", "Error making batch request", "");
      e.printStackTrace();
    }
    stopGDataTiming();
    printTaskResults("Last 30 days", "kWh", "OK");
  }
  
  /**
   * Returns a list with the 30 days of daily energy prior to the passed timestamp.  
   * @param currTime The time that we go backward from. 
   * @return A list of 30 integers containing daily energy for a 24 hour period. 
   */
  private List<Integer> getDailyEnergy(XMLGregorianCalendar currTime) {
    WattDepotClient client = this.wattDepotService.getClient();
    List<Integer> energies = new ArrayList<Integer>();
    // Make a new timestamp for the previous day with hours, mins, secs, and millisecs set to zero.
    XMLGregorianCalendar startDay = Tstamp.makeTimestamp();
    startDay.setHour(0);
    startDay.setMinute(0);
    startDay.setSecond(0);
    startDay.setMillisecond(0);
    // Now gather the energy data from the past thirty days and add to spreadsheet.
    for (int i = 0; i < 30; i++) {
      XMLGregorianCalendar end = Tstamp.incrementDays(startDay, (i * -1));
      XMLGregorianCalendar begin = Tstamp.incrementDays(startDay, ((i + 1) * -1));
      Integer energy = 0;
        // Use 0 for the sampling interval, that tells server to use energy counters.
        try {
          energy = (int) client.getEnergyConsumed(sourceName, begin, end, 0);
          System.out.format("%s Energy for %s from %s to %s is %s%n", 
              getTimestamp(), sourceName, begin, end, energy);
        }
        catch (WattDepotClientException e) {
          System.out.format("Failed to get energy for %s for day %s. Retrying after 5 secs.%n", 
              sourceName, begin);
          try {
            Thread.sleep(5000);
            energy = (int) client.getEnergyConsumed(sourceName, begin, end, 0);
            System.out.format("%s Energy for %s from %s to %s is %s%n", 
                getTimestamp(), sourceName, begin, end, energy);
          }
          catch (Exception f) {
            System.out.format("Failed to get energy for %s for day %s. Returning 0.%n", 
                sourceName, begin);
            f.printStackTrace();
            energy = 0;
          }

        }

      energies.add(energy);
    }
    return energies;
  }

}
